package com.young.weixin.service.impl;

import com.young.interfaces.log.annotation.Log;
import com.young.weixin.configure.WxConfigure;
import com.young.weixin.model.AccessTokenHolder;
import com.young.weixin.model.WxMessageRequest;
import com.young.weixin.model.wxrpc.response.GetAccessTokenResponse;
import com.young.weixin.rpc.IWxBaseRpc;
import com.young.weixin.service.IWxBaseService;
import com.young.weixin.util.WxUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 基础服务
 *
 * @author wangjiyu
 * @date 2021/10/5 13:30
 */
@Service
public class WxBaseServiceImpl implements IWxBaseService {

    private static final Logger logger = LoggerFactory.getLogger(WxBaseServiceImpl.class);
    /**
     * access_token对象
     */
    private static volatile AccessTokenHolder accessTokenHolder = null;

    /**
     * 微信基础rpc接口
     */
    @Autowired
    private IWxBaseRpc wxBaseRpc;
    /**
     * 配置
     */
    @Autowired
    private WxConfigure wxConfigure;

    /**
     * 微信服务端配置校验
     *
     * @param wxMessageRequest
     * @return 响应结果
     */
    @Log("微信服务端配置校验")
    @Override
    public String serverCheck(WxMessageRequest wxMessageRequest) {
        //1.获取经排序后的字符串
        String verifyStr = WxUtil.buildParamSortStr(wxConfigure.getToken(), wxMessageRequest.getTimestamp(), wxMessageRequest.getNonce());
        //2.sha1加密
        String verifyStrSha = DigestUtils.sha1Hex(verifyStr);
        //校验
        if (!verifyStrSha.equals(wxMessageRequest.getSignature())) {
            logger.error("[微信服务端配置校验] 加密结果与入参不一致,安全校验未通过,返回失败");
            //校验失败, 阻断
            return "error";
        }
        logger.info("[微信服务端配置校验] 服务器配置校验通过");
        //成功则返回入参中的随机字符串
        return wxMessageRequest.getEchostr();
    }



    /**
     * 获取微信access_token
     *
     * @return access_token
     */
    @Log("获取access_token")
    @Override
    public String getAccessToken() {
        // 优先从缓存中取
        if (accessTokenHolder != null && accessTokenHolder.isValid()) {
            logger.info("[获取access_token] 缓存的access_token仍然有效,返回access_token={}", accessTokenHolder.getAccessToken());
            return accessTokenHolder.getAccessToken();
        }
        synchronized (WxBaseServiceImpl.class) {
            // 双重校验, 再一次判断缓存是否有效, 避免并发带来的重复调用
            if (accessTokenHolder != null && accessTokenHolder.isValid()) {
                logger.info("[获取access_token] 存在并发查询,并发块中命中缓存,返回access_token={}", accessTokenHolder.getAccessToken());
                return accessTokenHolder.getAccessToken();
            }
            // 调用微信接口获取token
            GetAccessTokenResponse response = wxBaseRpc.getAccessToken();
            if (response != null && response.isSuccess()) {
                // 缓存access_token
                accessTokenHolder = AccessTokenHolder.build(response.getAccess_token(), response.getExpires_in());
                logger.info("[获取access_token] 调用微信接口查询access_token={}", response.getAccess_token());
                return response.getAccess_token();
            }
        }
        logger.warn("[获取access_token] 查询access_token失败,返回null");
        return null;
    }
}
